﻿/**
*    Copyright (C) 2008  Chase Kernan 
*    chase.kernan@gmail.com
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
*/

package com.chasekernan.hxnova.componenteditor;

import com.chasekernan.hxnova.core.components.Armor;
import com.chasekernan.hxnova.core.components.Component;
import com.chasekernan.hxnova.core.components.ComponentSet;
import com.chasekernan.hxnova.core.components.Hull;
import com.chasekernan.hxnova.core.races.ResearchCosts;
import com.chasekernan.hxnova.core.races.TechLevel;
import com.chasekernan.hxnova.core.stars.Concentrations;
import flash.events.Event;
import org.aswing.JOptionPane;
import org.aswing.JSpacer;
import swhx.Connection;
import flash.Lib;
import flash.net.DynamicPropertyOutput;
import org.aswing.AsWingConstants;
import org.aswing.AsWingManager;
import com.chasekernan.hxnova.componenteditor.details.EnginePanel;
import org.aswing.border.EmptyBorder;
import org.aswing.border.TitledBorder;
import org.aswing.event.InteractiveEvent;
import org.aswing.event.ListItemEvent;
import org.aswing.geom.IntDimension;
import org.aswing.geom.IntPoint;
import org.aswing.GridLayout;
import org.aswing.Insets;
import org.aswing.JAccordion;
import org.aswing.JAdjuster;
import org.aswing.JButton;
import org.aswing.JLabel;
import org.aswing.JList;
import org.aswing.JPanel;
import org.aswing.JTextArea;
import org.aswing.JTextField;

class ComponentEditorPanel extends JPanel {
    
    public static var INSTANCE : ComponentEditorPanel;
    
    public var editedComponent : Component;
    
    private var componentsList : JAccordion;
    private var individualLists : Hash<JList>;
    
    private var basicsPanel : JPanel;
    private var nameInput : JTextField;
    private var editDescription : JButton;
    private var pictureInput : JTextField;
    private var resourceInput : JAdjuster;
    private var mineralInputs : Hash<JAdjuster>;
    private var massInput : JAdjuster;
    private var techLevelInputs : Hash<JAdjuster>;
    
    private var setRaceAvailabilityButton : JButton;
    private var raceAvailabilityWindow : RaceAvailabilityWindow;
    
    private var newComponentButton : JButton;
    private var removeComponentButton : JButton;
    private var newComponentWindow : NewComponentWindow;
    
    private var saveComponentsButton : JButton;
    private var loadComponentsButton : JButton;
    
    private var allBasicComponents : Array<Dynamic>;
    
    private var detailsPanel : DetailsPanel;
    
    public function new() {
        super();
        
        INSTANCE = this;
        
        editedComponent = null;
        
        setSize(new IntDimension(825, 600));
        
        setupComponentsList();
        setupBasicsPanel();
        setupHandlers();
        setupBasicEnables();
    }
    
    private function setupComponentsList() {
        //SETUP COMPONENTS LIST ON LEFT
        componentsList = new JAccordion();
        componentsList.setLocation(new IntPoint(5, 5));
		componentsList.setSize(new IntDimension(200, 590));
		componentsList.setPreferredSize(new IntDimension(200, 590));
        componentsList.setBorder(new EmptyBorder(null, new Insets(5, 5, 5, 5)));
        
        
        individualLists = new Hash();
        
        for (cType in ComponentSet.COMPONENT_TYPES) {
            var list : JList = new JList();
            
            var className = getClassString(cType);
            list.setName(className);
            
            list.addEventListener(ListItemEvent.ITEM_CLICK, listClicks);
            
            individualLists.set(className, list);
            componentsList.append(list);
        }
        
        updateComponentsList();
        append(componentsList);
    }
    
    private function setupBasicsPanel() {
        //SETUP BASICS PANEL IN CENTER
        var numRows = 8 + Concentrations.MINERAL_TYPES.length + ResearchCosts.TECH_TYPES.length;
        
        basicsPanel = new JPanel(new GridLayout(numRows, 2, 5, 5));
        
        basicsPanel.setLocation(new IntPoint(205, 5));
        basicsPanel.setSize(new IntDimension(280, 32 * numRows + 10));
        basicsPanel.setPreferredSize(new IntDimension(280, 32 * numRows + 10));
        basicsPanel.setBorder(new EmptyBorder(new TitledBorder(new EmptyBorder(new Insets(5, 5, 5, 5)), "Basics"), new Insets(5, 5, 5, 5)));
        
        
        nameInput = new JTextField("");
        nameInput.setMaxChars(40);
        //nameInput.setEnabled(false);
        nameInput.setEditable(false);
        nameInput.setSize(new IntDimension(140, 21));
        nameInput.setPreferredSize(new IntDimension(140, 21));
        
		editDescription = new JButton("Edit Description");
        
        pictureInput = new JTextField("");
        pictureInput.setMaxChars(100);
        pictureInput.setSize(new IntDimension(140, 21));
        pictureInput.setPreferredSize(new IntDimension(140, 21));
        
        resourceInput = new JAdjuster(5);
        resourceInput.setMinimum(0);
        resourceInput.setMaximum(10000);
        resourceInput.setValue(0);
        
        mineralInputs = new Hash();
        for (minType in Concentrations.MINERAL_TYPES) {
            var input = new JAdjuster(5);
            input.setMinimum(0);
            input.setMaximum(10000);
            input.setValue(0);
            
            mineralInputs.set(minType, input);
        }
        
        techLevelInputs = new Hash();
        for (techType in ResearchCosts.TECH_TYPES) {
            var input = new JAdjuster(2);
            input.setMinimum(0);
            input.setMaximum(TechLevel.MAX_LEVEL);
            input.setValue(0);
            
            techLevelInputs.set(techType, input);
        }
        
        massInput = new JAdjuster(5);
        massInput.setValue(0);
        massInput.setMinimum(0);
        massInput.setMaximum(10000);
        
        newComponentButton = new JButton("New Component");
        removeComponentButton = new JButton("Remove Component");
        
        setRaceAvailabilityButton = new JButton("Set Race Availability");
        
        saveComponentsButton = new JButton("Save All Components");
        loadComponentsButton = new JButton("Load Components");
        
        //appending by row
        
        basicsPanel.append(setupDefaultLabel("Name"));
        basicsPanel.append(nameInput);
        
        basicsPanel.append(new JSpacer());
        basicsPanel.append(editDescription);
        
        basicsPanel.append(setupDefaultLabel("Picture"));
        basicsPanel.append(pictureInput);
        
        basicsPanel.append(setupDefaultLabel("Resource Cost"));
        basicsPanel.append(resourceInput);
        
        for (minType in Concentrations.MINERAL_TYPES) {
            var caps = minType.charAt(0).toUpperCase() + minType.substr(1);
            
            basicsPanel.append(setupDefaultLabel(caps + " Cost"));
            basicsPanel.append(mineralInputs.get(minType));
        }
        
        basicsPanel.append(setupDefaultLabel("Mass"));
        basicsPanel.append(massInput);
        
        for (techType in ResearchCosts.TECH_TYPES) {
            var caps = techType.charAt(0).toUpperCase() + techType.substr(1);
            
            basicsPanel.append(setupDefaultLabel(caps + " Level"));
            basicsPanel.append(techLevelInputs.get(techType));
        }
        
        basicsPanel.append(new JLabel(""));
        basicsPanel.append(setRaceAvailabilityButton);
        
        basicsPanel.append(newComponentButton);
        basicsPanel.append(removeComponentButton);
               
        basicsPanel.append(saveComponentsButton);
        basicsPanel.append(loadComponentsButton);
        
        append(basicsPanel);
    }
    
    private function setupBasicEnables() {
        //array used here for enabling/disabling components easily
        allBasicComponents = [nameInput, editDescription, pictureInput, resourceInput, massInput, setRaceAvailabilityButton];
        for (minType in Concentrations.MINERAL_TYPES) allBasicComponents.push(mineralInputs.get(minType));
        for (techType in ResearchCosts.TECH_TYPES) allBasicComponents.push(techLevelInputs.get(techType));
        
        //no component is selected to star with
        setAllEnabled(false);
    }
        
    private function setupHandlers() {
        newComponentButton.addActionListener(onClickNewComponent);
        setRaceAvailabilityButton.addActionListener(onClickRaceAvailability);
        removeComponentButton.addActionListener(removeCurrentComponent);
        Lib.current.addEventListener(Event.ENTER_FRAME, onEnterFrame);
        saveComponentsButton.addActionListener(onClickSaveComponents);
        loadComponentsButton.addActionListener(onClickLoadComponents);
		editDescription.addActionListener(onEditDescription);
    }
	
	private var editDescriptionWindow : DescriptionWindow;
	
	private function onEditDescription(?e : Dynamic) {
		editDescriptionWindow = new DescriptionWindow(this);
		editDescriptionWindow.addEventListener(DescriptionWindow.OK, onDescriptionOK);
		editDescriptionWindow.addEventListener(DescriptionWindow.CANCEL, onDescriptionCancel);
		editDescriptionWindow.setDescription(editedComponent.description);
		editDescriptionWindow.show();
	}
	
	private function onDescriptionOK(?e : Dynamic) {
		editedComponent.description = editDescriptionWindow.getDescription();
		editDescriptionWindow.tryToClose();
	}
	
	private function onDescriptionCancel(?e : Dynamic) {
		editDescriptionWindow.tryToClose();
	}
    
    /**
        Runs through all of the children in the basics panel and the specifics 
        panel and disables/enables them.
    **/
    private function setAllEnabled(enabled : Bool) {
        for (child in allBasicComponents) child.setEnabled(enabled);
        if (detailsPanel != null) {
            for (child in detailsPanel.allInputs) child.setEnabled(enabled);
        }
    }
    
    /**
        Switches the ui to editing the given component.
    **/
    public function switchTo(c : Component) {
        if (detailsPanel != null) {
            remove(detailsPanel);
            detailsPanel = null;
        }
        
        setAllEnabled(true);
        
        editedComponent = c;
        
        //setup details panel.
        var newType = componentsList.getSelectedComponent().getName();
        detailsPanel = DetailsPanel.getDetailsPanel(newType);
        if (detailsPanel != null) {
            detailsPanel.loadFromComponent();
            append(detailsPanel);
        }
        
        disableForDefensesAndScanner();
        
        loadFromComponent();
    }
    
    //defenses and star scanner costs and mass can be changed here
    private function disableForDefensesAndScanner() {
        var current = componentsList.getSelectedComponent().getName();
        
        if (current == "Defense" || current == "StarScanner") {
            resourceInput.setEnabled(false);
            massInput.setEnabled(false);
            for (minType in Concentrations.MINERAL_TYPES) {
                mineralInputs.get(minType).setEnabled(false);
            }
        }
    }
    
    private function onEnterFrame(?e : Dynamic) {
        saveToComponent();
    }
    
    private function removeCurrentComponent(?e : Dynamic) {
        if (editedComponent == null) return;
        
        setAllEnabled(false);
        ComponentSet.removeComponent(editedComponent);
        updateComponentsList();
        
        editedComponent = null;
    }
    
    private function saveToComponent(?e : Dynamic) {
        if (editedComponent == null) return;
        
        //editedComponent.name = nameInput.getText();
        editedComponent.picture = pictureInput.getText();
        
        editedComponent.resourceCost = resourceInput.getValue();
        for (minType in Concentrations.MINERAL_TYPES) {
            editedComponent.mineralCost.setValue(minType, mineralInputs.get(minType).getValue());
        }
        editedComponent.mass = massInput.getValue();
        
        for (techType in ResearchCosts.TECH_TYPES) {
            editedComponent.requiredTech.setLevel(techType, techLevelInputs.get(techType).getValue());
        }
        
        if (detailsPanel != null) detailsPanel.saveToComponent();
    }
    
    private function loadFromComponent(?e : Dynamic) {
        if (editedComponent == null) return;
        
        nameInput.setText(editedComponent.name);
        pictureInput.setText(editedComponent.picture);
        
        resourceInput.setValue(editedComponent.resourceCost);
        for (minType in Concentrations.MINERAL_TYPES) {
            mineralInputs.get(minType).setValue(editedComponent.mineralCost.getValue(minType));
        }
        massInput.setValue(editedComponent.mass);
        
        for (techType in ResearchCosts.TECH_TYPES) {
            techLevelInputs.get(techType).setValue(editedComponent.requiredTech.getLevel(techType));
        }
        
        if (detailsPanel != null) detailsPanel.loadFromComponent();
    }
    
    public static function setupDefaultLabel(name : String) : JLabel {
        var label = new JLabel(name);
        label.setHorizontalAlignment(/*AsWingConstants.LEFT*/ 2);
        return label;
    }
    
    private function listClicks(e : ListItemEvent) {
        saveToComponent();
        switchTo(ComponentSet.getComponentByName(e.getCell().getCellValue()));
    }
    
    private function updateComponentsList() {
        for (cType in ComponentSet.COMPONENT_TYPES) {
            var names = new Array<String>();
            for (c in ComponentSet.getAllComponentsOfType(cType)) names.push(c.name);
            
            individualLists.get(getClassString(cType)).setListData(names);
        }
    }
    
    private function onClickRaceAvailability(?e : Dynamic) {
        raceAvailabilityWindow = new RaceAvailabilityWindow(AsWingManager.getRoot());
        raceAvailabilityWindow.show();
        
    }
    
    //NEW COMPONENT WINDOW
    private function onClickNewComponent(?e : Dynamic) {
        newComponentWindow = new NewComponentWindow(AsWingManager.getRoot());
        newComponentWindow.show();
        
        newComponentWindow.addEventListener(NewComponentWindow.OK, onNewComponentOK);
        newComponentWindow.addEventListener(NewComponentWindow.CANCEL, onNewComponentCancel);
    }
    
    private function onNewComponentOK(?e : Dynamic) {
        var type = newComponentWindow.getComponentType();
        var name = newComponentWindow.getComponentName();
        var componentClass = Type.resolveClass(
                "com.chasekernan.hxnova.core.components." + type);
        var component = Type.createInstance(componentClass, [name]);
        ComponentSet.addComponent(component);
        
        component.picture = "data/images/components/" + type + "/" + name + ".png";
		if (componentClass == Hull) {
			var hull = cast(component, Hull);
			hull.backgroundPic = "data/images/components/" + type + "/" + name + "_background.png";
		}
        
        componentsList.setSelectedComponent(individualLists.get(type));
        
        switchTo(component);
        updateComponentsList();
        closeNewComponentWindow();
    }
    
    private function onNewComponentCancel(?e : Dynamic) {
        closeNewComponentWindow();
    }
    
    private function closeNewComponentWindow(?e : Dynamic) {
        newComponentWindow.tryToClose();
        newComponentWindow = null;
    }
    
    /**
        Returns true if the name hasn't been used yet.
    **/
    public static function checkName(name : String) : Bool {
        try {
            var c = ComponentSet.getComponentByName(name);
            return c == null;
        } catch (e : Dynamic) {
            return true;
        }
    }
    
    public static function getClassString(c : Class < Dynamic > ) : String {
        var fullName = Type.getClassName(c);
        return fullName.substr(fullName.lastIndexOf(".") + 1);
    }
    
    public static function getComponentClassNames() : Array < String > {
        var a = new Array<String>();
        for (cType in ComponentSet.COMPONENT_TYPES) a.push(getClassString(cType));
        return a;
    }
    
    private function onClickSaveComponents(?e : Dynamic) {
        var cnx = Connection.desktopConnect();
        try {
			cnx.Base.save.call([ComponentSet.writeToXml().toString()]);
		} catch (e : Dynamic) {
			trace(e);
		}
    }
    
    private function onClickLoadComponents(?e : Dynamic) {
        setAllEnabled(false);
        editedComponent = null;
        
        try {
            var cnx = Connection.desktopConnect();
            var data = cnx.Base.load.call([]);
            ComponentSet.readFromXml(Xml.parse(data).firstElement());
        
            updateComponentsList();
        } catch (e : Dynamic) {
            JOptionPane.showMessageDialog("Error", "An error occured when trying to read the components file: " + e);
        }
    }
    
}